TerraformでAmazon ECSをデプロイする時のALBターゲットグループ関連付けエラーを解消してみた

TerraformでAmazon ECSをデプロイする時のALBターゲットグループ関連付けエラーを解消してみた

Amazon ECSのデプロイの際に、「ALBがターゲットグループと関連づけられていない」というエラーが発生しました。コード上ではALBとターゲットグループは関連付けられていましたが、ALB側の書き方に問題があるケースだったので、ここで紹介します。
Clock Icon2024.07.17

TerraformでAmazon ECSがデプロイできない

おのやんです。

TerraformでAmazon ECS(以下、ECS)のサービスをデプロイしようとした時に、ALBとターゲットグループの関連付けが原因でデプロイできないことがあります。

terraform planコマンドでTerraformコードのエラーの多くを検知できますが、今回はterraform planで検知できるものではありませんでした。また、Application Load Balancer(以下、ALB)とターゲットグループの関連付けはエラーとは直接関係なかったので、解決までにしばらく時間がかかりました。

ということで、「こういう場合でもterraform applyのエラーになるよ〜」という共有の気持ちで、今回紹介します

エラー内容

ALBとECSをTerraformで記述している状態で、terraform applyを実行すると、以下のエラーが出ました

% terraform apply
...
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m20s elapsed]
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m30s elapsed]
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m40s elapsed]
module.ecs.aws_ecs_service.ecs_service_web: Still creating... [3m50s elapsed]

Error: creating ECS Service (aws-test-ecs-service-web): InvalidParameterException: The target group with targetGroupArn arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXX:targetgroup/aws-test-tg-web/XXXXXXXX does not have an associated load balancer.
│ 
│   with module.ecs.aws_ecs_service.ecs_service_web,
│   on ../modules/ecs/main.tf line 208, in resource "aws_ecs_service" "ecs_service_web":208: resource "aws_ecs_service" "ecs_service_web" {

The target group with targetGroupArn arn:aws... does not have an associated load balancer.とあるので、ALBとターゲットグループを関連づけていないことが原因と書いてあるのですが、私の場合はECSでもALBでもALB・ターゲットグループの関連付けは設定していました。

ecs.tf
resource "aws_ecs_service" "aws_test_ecs_service_web" {
  name             = "aws-test-ecs-service-web"
  cluster          = aws_ecs_cluster.ecs_cluster.arn
  launch_type      = "FARGATE"
  task_definition  = aws_ecs_task_definition.ecs_task_definition_web.arn
  desired_count    = 1
  platform_version = "1.4.0"

  network_configuration {
    assign_public_ip = false
    security_groups  = [module.sg_ecs.security_group_id]
    subnets          = var.private_subnets
  }

  load_balancer {
    target_group_arn = var.alb_tg_web_arn
    container_name   = "nginx"
    container_port   = 80
  }
}
alb.tf
resource "aws_lb" "aws_test_alb" {
  name               = "aws-test-alb"
  internal           = false
  load_balancer_type = "application"
}

resource "aws_lb_listener" "aws_test_listener_public_http" {
  load_balancer_arn = aws_lb.public.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
    type = "redirect"
    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
    target_group_arn = aws_lb_target_group.aws_test_tg.arn
  }
}

resource "aws_lb_target_group" "aws_test_tg" {
  name                 = "aws-test-tg"
  vpc_id               = var.vpc_id
  target_type          = "ip"
  port                 = 80
  protocol             = "HTTP"
  deregistration_delay = 300
  health_check {
    path    = "/"
    matcher = "200-399"
    timeout = "25"
  }
}

エラー原因・解消

上記のコードを見て気づく方もいると思いますが、今回のエラーはALBのデフォルトアクションがredirectの設定になっていることが原因です。なので、Terraformコードの下記の部分をforwardの設定に変えると、正常にデプロイすることができました。

alb.tf
resource "aws_lb_listener" "aws_test_listener_public_http" {
  load_balancer_arn = aws_lb.public.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
-    type = "redirect"
-    redirect {
-      port        = "443"
-      protocol    = "HTTPS"
-      status_code = "HTTP_301"
-    }
+    type             = "forward"
    target_group_arn = aws_lb_target_group.aws_test_tg.arn
  }
}

そもそも、target_group_arnredirectの設定では使用しませんので、ALBの設定自体が間違えていたことになります。リダイレクトの場合、クライアントからの通信は指定された新しいURLに直接リダイレクトされるため、ターゲットグループは関係ありません。

target_group_arn - (Optional) ARN of the Target Group to which to route traffic. Specify only if type is forward and you want to route to a single target group. To route to one or more target groups, use a forward block instead. Cannot be specified with forward.

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_rule

例えば、クライアントからのアクセスをHTTPSにリダイレクトした後にターゲットグループに転送するには、2つのリスナーを設定する必要があります。1つ目のリスナーでHTTPからHTTPSにリダイレクト、もう1つのHTTPSリスナーでターゲットグループにトラフィックを転送します。

alb.tf
#------------------------------------------------------------------------------#
# HTTPSへリダイレクト
#------------------------------------------------------------------------------#

resource "aws_lb_listener" "aws_test_listener_public_http" {
  load_balancer_arn = aws_lb.public.arn
  port              = 80
  protocol          = "HTTP"

  default_action {
    type = "redirect"
    redirect {
      port        = "443"
      protocol    = "HTTPS"
      status_code = "HTTP_301"
    }
  }
}

#------------------------------------------------------------------------------#
# ターゲットグループへ転送
#------------------------------------------------------------------------------#

resource "aws_lb_listener" "aws_test_listener_public_https" {
  load_balancer_arn = aws_lb.public.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-2016-08"
  certificate_arn   = "arn:aws:acm:ap-northeast-1:<account-id>:certificate/<certificate-id>"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.aws_test_tg.arn
  }
}

ドキュメントを読もう

今回のエラーは、ドキュメントをよく読んでいれば避けられるものでした。TerraformのLinterに頼るのもいいですが、コードの実装の際には公式のドキュメントを参照するようにしましょう。デプロイ時の不要なエラーを回避できるかもしれません。では!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.